package cn.seamus.marksman.http;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.protocol.HttpContext;

public class AuthProxyHttpExecuter extends AbstractHttpExecuter {
    private static Log logger = LogFactory.getLog(AuthProxyHttpExecuter.class);

    private String proxyHost;
    private int proxyPort;
    private String proxyUsername;
    private String proxyPassword;
    private boolean isLaxRedirect;

    /*
     * (non-Javadoc)
     * 
     * @see cn.seamus.marksman.http.AbstractHttpExecuter#createHttpHost()
     */
    @Override
    protected HttpHost createHttpHost(String host, int port, String protocal) {
        HttpHost target = new HttpHost(host, port, protocal);
        return target;
    }

    /*
     * (non-Javadoc)
     * 
     * @see cn.seamus.marksman.http.AbstractHttpExecuter#createHttpGet()
     */
    @Override
    protected HttpGet createHttpGet(String path) {
        HttpHost proxy = new HttpHost(proxyHost, proxyPort);

        RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
        HttpGet httpget = new HttpGet(path);
        httpget.setConfig(config);

        return httpget;
    }

    @Override
    protected HttpPost createHttpPost(String path) {
        HttpHost proxy = new HttpHost(proxyHost, proxyPort);

        RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
        HttpPost httppost = new HttpPost(path);
        httppost.setConfig(config);

        return httppost;
    }

    @Override
    protected CloseableHttpClient retrieveHttpClient() {
        CloseableHttpClient httpclient = clientLocal.get();

        if (httpclient == null) {
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(new AuthScope(proxyHost, proxyPort), new UsernamePasswordCredentials(
                    proxyUsername, proxyPassword));

            // Create a local instance of cookie store
            CookieStore cookieStore = new BasicCookieStore();
            // Populate cookies if needed
            BasicClientCookie cookie = new BasicClientCookie("name", "value");
            cookie.setVersion(0);
            cookie.setDomain(".allyouneed.com");
            cookie.setPath("/");
            cookieStore.addCookie(cookie);

            // Self-definition redirect strategy.
            RedirectStrategy redirectStrategy = new DefaultRedirectStrategy() {
                @Override
                public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context)
                        throws ProtocolException {
                    boolean isRedirect = false;
                    try {
                        isRedirect = super.isRedirected(request, response, context);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (!isRedirect) {
                        int responseCode = response.getStatusLine().getStatusCode();
                        if (responseCode == 301 || responseCode == 302) {
                            return true;
                        }
                    }
                    return isRedirect;
                }
            };

            if (isLaxRedirect) {
                httpclient = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy())
                        .setDefaultCredentialsProvider(credsProvider).build();
            } else {
                httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
            }

            clientLocal.set(httpclient);
        }

        return httpclient;
    }

    /**
     * @return the proxyHost
     */
    public String getProxyHost() {
        return proxyHost;
    }

    /**
     * @param proxyHost
     *            the proxyHost to set
     */
    public void setProxyHost(String proxyHost) {
        this.proxyHost = proxyHost;
    }

    /**
     * @return the proxyPort
     */
    public int getProxyPort() {
        return proxyPort;
    }

    /**
     * @param proxyPort
     *            the proxyPort to set
     */
    public void setProxyPort(int proxyPort) {
        this.proxyPort = proxyPort;
    }

    /**
     * @return the proxyUsername
     */
    public String getProxyUsername() {
        return proxyUsername;
    }

    /**
     * @param proxyUsername
     *            the proxyUsername to set
     */
    public void setProxyUsername(String proxyUsername) {
        this.proxyUsername = proxyUsername;
    }

    /**
     * @return the proxyPassword
     */
    public String getProxyPassword() {
        return proxyPassword;
    }

    /**
     * @param proxyPassword
     *            the proxyPassword to set
     */
    public void setProxyPassword(String proxyPassword) {
        this.proxyPassword = proxyPassword;
    }

    public boolean getIsLaxRedirect() {
        return isLaxRedirect;
    }

    public void setIsLaxRedirect(boolean isLaxRedirect) {
        this.isLaxRedirect = isLaxRedirect;
    }

}
